#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   conftest.py
@Time    :   2022/02/23 09:16:36
@Author  :   yangliang 
@Version :   1.0
@Contact :   yangl@genvict.com
@License :   (C)Copyright 2022-2025
@Desc    :   None
'''
import shutil
import sys
import os
import logging

from commDriver.jidianqi import JDQSerialController
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.abspath(os.path.dirname(curPath) + os.path.sep + ".")
sys.path.append(rootPath)
sys.path.append(os.path.join(curPath,'commDriver'))
sys.path.append(os.path.join(curPath,'data'))
sys.path.append(os.path.join(curPath,'commDriver/zlg'))
logging.info(sys.path)


# here put the import lib
import pytest
import sys
import os
import time
import datetime
import allure
from py._xmlgen import html
import traceback

# from commDriver.CAN import *
# from commDriver.TS_CAN import *
# from commDriver.power import *
from project_CAN_TC import *
import project_CAN_TC
from project_CAN_ZLG import *
import project_CAN_ZLG
from commDriver.zlg.zlgcan import *
from commDriver.zlg.zuds_test_main import *
from commDriver.power_2303 import *
from commDriver.power_it6720 import *
from commDriver.zlg.dbc import *
from commDriver.zlg.zlgdbc import *
from commDriver.m600_communicator import *

import Set_up


__Driver = {}

sys.dont_write_bytecode = True


# 这里我设置的级别是模块级别,也就是每个测试文件运行一次
# 可以设置为session,全部用例执行一次
@pytest.fixture(scope='session')
def Driver():
    global __Driver

    def init_can_driver():
        """初始化CAN驱动"""
        try:
            logging.info("open CAN_Driver".center(50, '-'))
            if Set_up.drive_type != ZCAN_USBCANFD_200U:
                project_rbs = real_CAN_TC(Set_up.drive_type,Set_up.configure_baudrate,TSMasterAPI.CHANNEL_INDEX.CHN1)
                project_rbs.load_dbc(Set_up.project_DBC_File_CAN, ASupportedChannelsBased = '0')
                project_rbs.register_event_canfd_T_pre(OnCANPreFDevent)
                project_rbs.register_event_canfd_T_R(OnCANPreFDevent_checkPCAN)
                project_rbs.connect_application()
                project_rbs.RBS_Config(Set_up.NetName,Set_up.EnableNode)
                project_rbs.start_rbs()
                project_rbs.write_db_signal(Set_up.NetName, 'ETCM', 'DhuInfoCanFr72', 'ETCSwitchReq', 1)
                # project_rbs.set_0x311_error = False

            else:
                project_rbs = real_CAN_ZLG(Set_up.drive_type,Set_up.drive_index,Set_up.chn_index,Set_up.can_abit,Set_up.can_bbit)
                project_rbs.Open_CAN()
                project_rbs.init_uds()
                project_rbs.register_signal_receiver(0x3E6, my_receive_callback(project_rbs))
                signal_configs = project_rbs.parse_dbc_to_list(Set_up.project_DBC_File_CAN)
                project_rbs.start_multiple_signal_loops(signal_configs)
                time.sleep(0.5)
                project_rbs.update_signal_data(0x90, signal_name='PwrModSts', value=2)
                project_rbs.update_signal_data(0x106, signal_name='VehSpdVld', value=1)
                project_rbs.update_signal_data(0x107, [0x00, 0x19, 0x03, 0x21, 0x09, 0x19, 0x20, 0x25])

            __Driver['CAN'] = project_rbs
            logging.info("open CAN_Driver success".center(50, '-'))
            return True
        except Exception as e:
            logging.error(f"初始化CAN驱动失败: {str(e)}")
            logging.error(traceback.format_exc())
            if 'project_rbs' in locals():
                project_rbs.close_can()
            logging.error("open CAN_Driver failed".center(50, '-'))
            return False

    # 初始化CAN驱动
    if not init_can_driver():
        pytest.exit("CAN驱动初始化失败")
        
    def init_uds_driver():
        """初始化UDS驱动"""
        try:
            if Set_up.drive_type == ZCAN_USBCANFD_200U:
                diag = project_rbs
                diagfun = project_rbs
            else:
                SupportFD = 0 if Set_up.CAN_Type == 'CAN' else 1
                Maxdlc = 8 if Set_up.CAN_Type == 'CAN' else 16
                diag = TSCAN_UDS(ASupportFD=SupportFD, AMaxdlc=Maxdlc, 
                                reqID=Set_up.reqID, resID=Set_up.resID, AFctID=Set_up.AFctID)
                
            __Driver['UDS'] = __Driver['UDSFun'] = diag
            logging.info("Creat UDS_Handle successful".center(50, '-'))
            return True
        except Exception as e:
            logging.error(f"初始化UDS驱动失败: {str(e)}")
            logging.error(traceback.format_exc())
            logging.error("Creat UDS_Handle failed".center(50, '-'))
            return False
            
    # 初始化UDS驱动
    if not init_uds_driver():
        pytest.exit("UDS驱动初始化失败")

    # __Driver['CAN'].set_FDmode(TSMasterAPI.CHANNEL_INDEX.CHN1, True, True, Maxdlc)
    # __Driver['CAN'].set_FDmode(TSMasterAPI.CHANNEL_INDEX.CHN2, True, True, Maxdlc)


    def init_power_driver():
        """初始化电源驱动"""
        try:
            logging.info("open power_Driver".center(50, '-'))
            if Set_up.power_Type == '2303':
                project_power = PowerSupplyController(Set_up.gpib_address)
                project_power.turn_on_power()
                project_power.set_voltage(12)
            else:
                project_power = IT6720SerialController()
                project_power.connect()
            
            __Driver['power'] = project_power
            time.sleep(1)
            logging.info("open power_Driver success".center(50, '-'))
            return True
        except Exception as e:
            logging.error(f"初始化电源驱动失败: {str(e)}")
            logging.error(traceback.format_exc())
            try:
                if 'project_power' in locals():
                    project_power.turn_off_power()
            except Exception:
                pass
            logging.error("open power_Driver failed".center(50, '-'))
            return False
            
    # 初始化电源驱动
    if not init_power_driver():
        pytest.exit("电源驱动初始化失败")

    def init_m600t_driver():
        """初始化M600T设备驱动"""
        try:
            logging.info("open M600T_Driver".center(50, '-'))
            logging.info(f"尝试连接M600T设备: 端口={Set_up.M600Tport}, 波特率={Set_up.M600Tbaudrate}, 超时={Set_up.M600TTimeOut}")
            project_m600t = M600Communicator(Set_up.M600Tport,Set_up.M600Tbaudrate,Set_up.M600TTimeOut)
            project_m600t.InitRSU()
            __Driver['M600'] = project_m600t
            time.sleep(0.5)
            logging.info("open M600T_Driver success".center(50, '-'))
            
            return True
        except Exception as e:
            logging.error(f"M600T设备初始化失败: {str(e)}")
            logging.error(traceback.format_exc())
            try:
                if 'project_m600t' in locals():
                    project_m600t.close()
                    logging.info("已关闭M600T设备连接")
            except Exception as e:
                logging.error(f"关闭M600T设备连接时出错: {str(e)}")
            logging.error("open M600T_Driver failed".center(50, '-'))
            return False
            
    # 初始化M600T设备驱动
    if not init_m600t_driver():
        pytest.exit("M600T设备初始化失败")

    yield __Driver
    if Set_up.drive_type == ZCAN_USBCANFD_200U:
        __Driver['CAN'].stop_multiple_signal_loops()
        __Driver['CAN'].close_can()
        logging.info("close CAN_Driver".center(50, '-'))
    else:
        __Driver['CAN'].dis_connect_application()
        logging.info("close CAN_Driver".center(50, '-'))

        __Driver['UDS'].UDS_can_delete()
        __Driver['UDSFun'].UDS_can_delete()

    logging.info("close CAN_Driver".center(50, '-'))


    
    # Init jidianqi
    try:
        logging.info("open jidianqi".center(50, '-'))
        project_jidianqi = JDQSerialController(Set_up.jidianqiPort,Set_up.jidianqiBaudrate,Set_up.jidianqiTimeOut)
        __Driver['jidianqi'] = project_jidianqi
        time.sleep(0.5)
        logging.info("open jidianqi success".center(50, '-'))
    except Exception as e:
        logging.info(traceback.print_exc())
        try:
            __Driver['jidianqi'].close()
        except Exception as e: 
            pass  
        logging.info("open jidianqi failed ".center(50, '-'))

    try:
        if Set_up.power_Type == '2303':
            __Driver['power'].turn_off_power()
        else:
            __Driver['power'].turn_off()
            __Driver['power'].close()
    except Exception as e: 
        pass  
    logging.info("close power_Driver".center(50, '-'))

    __Driver['power'].close()
    logging.info("close Power".center(50, '-'))


@pytest.fixture()
def action():
    blfname = datetime.datetime.now().strftime('%Y-%m-%d_%H_%M_%S') + '.blf'
    logging.info("测试用例开始".center(30, '*'))
    time.sleep(0.5)
    yield
    time.sleep(0.5)
    logging.info("测试用例结束".center(30, '*'))

@pytest.fixture()
def DismountFail():
    iStep = 1
    logging.info("设置防拆认证状态为失效".center(30, '*'))
    __Driver['power'].turn_off_power()
    time.sleep(0.5)
    __Driver['power'].turn_on_power()
    time.sleep(3)
    __Driver['CAN'].send_ETCActiveCmd(iStep)
    iStep, messageCount, data = __Driver['CAN'].GetMessageCount(iStep, 0x311, 2)
    logging.info("发送三次错误的UxCDismountData")
    for i in range(3):
        __Driver['CAN'].send_UXCDismountData(iStep, [0x00] * 8)
        time.sleep(1)
    __Driver['power'].turn_off_power()
    time.sleep(1)
    __Driver['power'].turn_on_power()
    time.sleep(5)
    yield
    pass
    
@pytest.fixture()
def BCMPower_Gear():
    __Driver['CAN'].write_db_signal('Vehicle_CAN', 'BCM', 'Left_BCM_0x12D', 'BCMPower_Gear_12D_S', 3)
    __Driver['CAN'].write_db_signal('Vehicle_CAN', 'BCM', 'Left_BCM_0x3D9', 'Total_Distance_3D9s5_S', 10)
    logging.info("设置BCMPower_Gear_12D_S为ON档,并等待3s".center(30, '*'))
    time.sleep(3)
    yield
    __Driver['CAN'].write_db_signal('Vehicle_CAN', 'BCM', 'Left_BCM_0x12D', 'BCMPower_Gear_12D_S', 1)
    __Driver['CAN'].write_db_signal('Vehicle_CAN', 'BCM', 'Left_BCM_0x3D9', 'Total_Distance_3D9s5_S', 10)
    logging.info("设置BCMPower_Gear_12D_S为OFF档,并等待0.5s".center(30, '*'))
    time.sleep(0.8)


@pytest.fixture()
def Fault_Injection():
    logging.info("采用故障注入,清除故障".center(30, '*'))
    __Driver['CAN2'].sendAndread_CMD_Shell(0x114,'profile 0',20)

    __Driver['CAN2'].sendAndread_CMD_Shell(0x114,'cmd set gExInj_AlignmentNeverDone_Enable 0 C 1 1',20)
    __Driver['CAN2'].sendAndread_CMD_Shell(0x114,'cmd set gExInj_AlignmentNeverDone_val 0 s 1 0',20)

    __Driver['CAN2'].sendAndread_CMD_Shell(0x114,'cmd set gExInj_AlignmentNotDone_Enable 0 C 1 1',20)
    __Driver['CAN2'].sendAndread_CMD_Shell(0x114,'cmd set gExInj_AlignmentNotDone_val 0 s 1 0',20)

    __Driver['CAN2'].sendAndread_CMD_Shell(0x114,'cmd set gExInj_VariantCodeDet_Enable 0 C 1 1',20)
    __Driver['CAN2'].sendAndread_CMD_Shell(0x114,'cmd set gExInj_VariantCodeDet_val 0 s 1 0',20)
    time.sleep(3)
    yield
    time.sleep(0.5)

@pytest.fixture()
def power_reset():
    logging.info("power reset".center(30, '*'))
    __Driver['power'].turn_off_power()
    time.sleep(0.5)
    __Driver['power'].turn_on_power()
    time.sleep(3)

@pytest.fixture(scope='function',autouse=False)
def default_session():
    time.sleep(2)
    with allure.step('Step1:Request [0x10,0x01]'):
        __Driver['UDS'].req_and_res_can(0x10, [0x01])

@pytest.fixture(scope='function',autouse=False)
def extend_session():
    time.sleep(2)
    with allure.step('Step1:Request [0x10,0x03]'):
        __Driver['UDS'].req_and_res_can(0x10, [0x03])

@pytest.fixture(scope='function',autouse=False)
def programming_session():
    time.sleep(2)
    with allure.step('Step1:Request [0x10,0x03]'):
        __Driver['UDS'].req_and_res_can(0x10, [0x03])
    time.sleep(0.1)
    __Driver['CAN'].unlock(__Driver,2)
    with allure.step('Step4:Request [0x10,0x02]'):
        __Driver['UDS'].req_and_res_can(0x10, [0x02])
    time.sleep(2)
    yield
    __Driver['UDS'].req_and_res_can(0x10, [0x01])


# @pytest.fixture(scope=“class”,autouse=True)
@pytest.fixture(scope='module',autouse=True)
def power_reset_for_class(): 
    __Driver['power'].turn_off_power()
    logging.info('power reset for module')
    time.sleep(1)
    __Driver['power'].turn_on_power()
    __Driver['power'].set_voltage(12)
    logging.info('Wait 5 seconds')
    time.sleep(5)
    

def pytest_configure(config):
    PowerSupplySolution = Set_up.Dut_Type
    # Add interface address and project info
    #TODO, below info import from common folder Comm_Config.py file
    config._metadata["Software version"] = Set_up.Dut_Type + ' - ' + Set_up.OBU_Software_Version
    config._metadata["boot version"] = Set_up.bootver
    config._metadata["Build tag"] = "XX.XX.XX.XX"
    config._metadata["SN"] = "test 0.0.0.1"
    config._metadata["Dut type"] = PowerSupplySolution
    config._metadata["Test time"] = datetime.datetime.now().date()

    # Delete Java_Home
    config._metadata.pop("Python")
    config._metadata.pop("Plugins")
    config._metadata.pop("Packages")

    if os.path.exists('../Radar_report.html') and os.path.getsize('../Radar_report.html') > 16000:
        '''拷贝allure-results'''
        source_path = "../allure-results"
        target_path = "../" + PowerSupplySolution + datetime.datetime.now().strftime("_%y%m%d%H%M")
        allure_target_path = target_path + "/allure-results"
        if not os.path.exists(target_path):
            # 如果目标路径不存在原文件夹的话就创建
            os.makedirs(allure_target_path)
        if os.path.exists(source_path):
            # 如果目标路径存在原文件夹的话就先删除
            # shutil.rmtree(allure_target_path)
            time.sleep(1)
            shutil.move(source_path, allure_target_path)

        '''拷贝Radar_report'''
        source_path = "../Radar_report.html"
        html_target_path = target_path + "/"
        time.sleep(1)
        shutil.move(source_path, html_target_path)

@pytest.fixture()
def set_rbs():
    logging.info("停止发送EDR报文".center(30, '*'))
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x74A',False) 
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x74A',False)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x751',False)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x752',False)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x753',False)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x75B',False)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x75C',False)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x75D',False)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x75E',False)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x75F',False)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x764',False)
    time.sleep(0.1)
    yield
    logging.info("开始发送EDR报文".center(30, '*'))
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x74A',True)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x751',True)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x752',True)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x753',True)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x75B',True)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x75C',True)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x75D',True)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x75E',True)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x75F',True)
    __Driver['CAN2'].Enable_rbs_message(Set_up.NetName,'EDR','EDR_0x764',True)


@pytest.mark.optionalhook
def pytest_html_results_summary(prefix, summary, postfix):
    prefix.extend([html.p("Tester: YangLiang")])
    prefix.extend([html.p("Report version: 0.0.1")])


@pytest.mark.optionalhook
def pytest_html_results_table_header(cells):
    cells.pop()

@pytest.mark.optionalhook
def pytest_html_results_table_row(report, cells):
    cells.pop()

@pytest.mark.hookwrapper
def pytest_runtest_makereport(item, call):
    outcome = yield
    report = outcome.get_result()
	
@pytest.fixture(scope="function", autouse=True)
def mod_header(request):
    item_name = request.node.nodeid.split("::")[-1]
    logging.info('\n-----------------')
    logging.info('Item name : %s' % item_name)
    
    if Set_up.drive_type == ZCAN_USBCANFD_200U:
        blfname = datetime.datetime.now().strftime('%Y-%m-%d_%H_%M_%S') + '.asc'
        __Driver['CAN'].start_logging(os.path.join(Set_up.root, f"blflog\{item_name}_{blfname}"))
    else:
        blfname = datetime.datetime.now().strftime('%Y-%m-%d_%H_%M_%S') + '.blf'
        log_path = os.path.join(Set_up.root, f"blflog\{item_name}_{blfname}")
        __Driver['CAN'].tsapp_start_logging(log_path)
    yield
    if Set_up.drive_type == ZCAN_USBCANFD_200U:
        __Driver['CAN'].stop_logging()
    else:
        __Driver['CAN'].tsapp_stop_logging()
    
    # # 根据测试结果决定是否删除日志文件
    # if request.node.rep_call.failed:
    #     logging.info("测试失败，日志文件保留: %s", log_path)
    # else:
    #     time.sleep(0.01)
    #     os.remove(log_path)
    #     # logging.info("测试成功，日志文件已删除: %s", log_path)

